package com.xyoto.community.service.impl;

import com.github.pagehelper.PageHelper;
import com.xyoto.community.cache.CacheInstruction;
import com.xyoto.community.config.TopicUserHotTableConfig;
import com.xyoto.community.constant.*;
import com.xyoto.community.dto.*;
import com.xyoto.community.entity.main.HotTopic;
import com.xyoto.community.entity.main.Topic;
import com.xyoto.community.entity.main.TopicFollow;
import com.xyoto.community.enums.*;
import com.xyoto.community.exception.ExceptionUtils;
import com.xyoto.community.mapper.main.*;
import com.xyoto.community.po.TotalDynamicListPO;
import com.xyoto.community.po.UserPO;
import com.xyoto.community.po.UserTitlePO;
import com.xyoto.community.pojo.Type2TopicUserHotTableInfo;
import com.xyoto.community.service.*;
import com.xyoto.community.utils.*;
import com.xyoto.community.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;


/**
 * ClassName:   话题Service接口实现类
 * Author:      挽风
 * Date:        2020
 * Copyright:   2020 by 挽风1.0版本
 * Description:
 *
 * @author Administrator
 */

@Service
@Slf4j
public class TopicServiceImpl implements TopicService {

    @Resource
    private HttpServletRequest httpServletRequest;

    @Resource
    private HttpServletRequest request;

    @Autowired
    private TopicMapper topicMapper;

    @Autowired
    TopicFollowMapper topicFollowMapper;

    @Autowired
    DynamicMapper dynamicMapper;

    @Autowired
    QuestionMapper questionMapper;

    @Autowired
    private HotTopicMapper hotTopicMapper;

    @Resource
    private XYOtoOss xyOtoOss;

    @Autowired
    private HotDynamicMapper hotDynamicMapper;

    @Autowired
    private UserMapper userMapper;

    @Resource
    private DynamicService dynamicService;

    @Resource
    private StudentAuthenticationMapper studentAuthenticationMapper;

    @Autowired
    private ContentCheckUtils contentCheckUtils;

    @Autowired
    private RedisCommonUtils redisCommonUtils;

    @Autowired
    private TopicUserHotTableConfig topicUserHotTableConfig;

    @Autowired
    private TopicUserHotService topicUserHotService;

    @Autowired
    private UserTitleService userTitleService;

    @Autowired
    private TopicHotDynamicCacheService topicHotDynamicCacheService;

    @Autowired
    private DynamicCacheService dynamicCacheService;

    @Autowired
    private TopicAllDynamicCacheService topicAllDynamicCacheService;

    @Autowired
    private TopicCacheService topicCacheService;

    @Autowired
    private UserTitleCacheService userTitleCacheService;


    /**
     * 根据话题id查询话题是否存在
     *
     * @param topicId 话题id
     * @return 数量
     */
    @Override
    public Integer getTopicIsExistById(Integer topicId) {
        return topicMapper.getTopicIsExistById(topicId);
    }

    /**
     * 话题列表
     *
     * @param pageDTO 分页dto
     * @return topicList
     */
    @Override
    public Result<PageUtils<TopicListVo>> getTopicList(PageDTO pageDTO) {
        PageHelper.startPage(pageDTO.getPageNum(), pageDTO.getPageSize());
        List<TopicListVo> topicListVos = topicMapper.getTopicList(pageDTO.getEndIndexId(), DeleteStatus.NO);
        // 填充需要统计的数据
        fillCount(topicListVos);
        return new Result<>(CommonEnum.SUCCESS, PageUtils.restPage(topicListVos));
    }

    /**
     * 给TopicListVo填充需要统计的数据
     *
     * @param topicListVos
     */
    @Override
    public void fillCount(List<TopicListVo> topicListVos) {
        for (TopicListVo topicListVo : topicListVos) {
            // 统计话题关注数
            topicListVo.setFollowCount(topicFollowMapper.countTopicFollow(topicListVo.getId(), FollowStatus.FOLLOW));
            // 统计话题下的动态数
            topicListVo.setDynamicCount(dynamicMapper.countDynamicByTopicIdAndStatusAndPersonal(
                    topicListVo.getId(), DeleteStatus.NO, PersonalStatus.VISIBLE_TO_ALL));
        }
    }

    /**
     * 保存话题关注/取消话题关注
     *
     * @param saveTopicFollowDTO
     * @return 保存成功
     */
    @Override
    public Result saveTopicFollow(SaveTopicFollowDTO saveTopicFollowDTO) {
        // 获取用户的id
        Integer userId = JwtUtils.getMemberIdByJwtToken(httpServletRequest);
        // 查询话题是否存在
        Topic topic = topicMapper.selectOneByTopicId(saveTopicFollowDTO.getTopicId());
        if (topic == null || topic.getDeleteStatus() == DeleteStatus.YES) {
            ExceptionUtils.error(TopicEnum.TOPIC_NOT_EXIST);
        }

        // 查询用户是否已经关注该话题
        TopicFollow topicFollow = topicFollowMapper.selectOneByUserIdAndTopicId(userId, topic.getId());

        if (topicFollow == null) {
            // 用户没关注该话题
            topicFollow = new TopicFollow(userId, topic.getId());
        }

        Short followStatus = topicFollow.getFollowStatus();
        if (Short.valueOf(FollowStatus.UN_FOLLOW).equals(followStatus)) {
            // 进行关注
            followStatus = FollowStatus.FOLLOW;
        } else {
            // 取关
            followStatus = FollowStatus.UN_FOLLOW;
        }
        topicFollow.setFollowStatus(followStatus);
        if (topicFollow.getId() == null) {
            // 新增关注话题记录
            Integer insert = topicFollowMapper.insertTopicFollow(topicFollow);
            if (insert < DatabaseOperationResult.SUCCESS) {
                log.error("【关注/取关失败】，新增记录到数据库失败，实体参数{}", topicFollow);
                ExceptionUtils.error(FollowEnum.FOLLOW_TOPIC_ERROR);
            }
        } else {
            // 修改关注话题记录
            Integer update = topicFollowMapper.updateTopicFollow(topicFollow);
            if (update < DatabaseOperationResult.SUCCESS) {
                log.error("【关注/取关失败】，修改数据库记录失败，实体参数{}", topicFollow);
                ExceptionUtils.error(FollowEnum.FOLLOW_TOPIC_ERROR);
            }
        }
        // 返回结果
        return Result.success();
    }

    /**
     * 获取话题详情
     *
     * @param topicId 话题id
     * @return 话题详情
     */
    @Override
    public Result<TopicDetailVo> getTopicDetail(Integer topicId) {
        //话题id不合法
        if (topicId == null || topicId <= 0) {
            return new Result(TopicEnum.TOPIC_NOT_EXIST);
        }

        TopicDetailVo topicDetailVo = topicMapper.selectDetailByTopicId(topicId, DeleteStatus.NO);
        if (topicDetailVo == null) {
            return new Result(TopicEnum.TOPIC_NOT_EXIST);
        }

        //获取关注数
        topicDetailVo.setFollowCount(topicFollowMapper.countTopicFollow(topicId, FollowStatus.FOLLOW));
        //获取动态个数
        topicDetailVo.setDynamicCount(dynamicMapper.countDynamicByTopicIdAndStatusAndPersonal(topicId, DeleteStatus.NO, PersonalStatus.VISIBLE_TO_ALL));
        //获取用户关注状态
        Integer userId = JwtUtils.getMemberIdByJwtToken(httpServletRequest);
        Short followStatus = topicFollowMapper.getUserFollowStatus(topicId, userId);

        if (followStatus != null && FollowStatus.FOLLOW == followStatus) {
            topicDetailVo.setFollowStatus(FollowStatus.FOLLOW);
        } else {
            //没关注过 或者关注后取消关注
            topicDetailVo.setFollowStatus(FollowStatus.UN_FOLLOW);
        }

        //获取榜单中的前四名
        Type2TopicUserHotTableInfo topicUserHotInfoByTopicId = topicUserHotTableConfig.getTopicUserHotInfoByTopicId(topicId);
        if (topicUserHotInfoByTopicId != null) {
            //转为List<Integer>
            List<Integer> list = new ArrayList<>();
            Set<Object> objects = redisCommonUtils.rangeByZSet(topicUserHotInfoByTopicId.getTableName(), 0, 3);
            for (Object object : objects) {
                list.add(Integer.parseInt(object.toString()));
            }
            //查询前四名的用户信息
            if (list.size() != 0) {
                List<UserPO> userPoList = userMapper.getUserSimpleList(list);
                topicDetailVo.setUserPoList(userPoList);
            } else {
                topicDetailVo.setUserPoList(new ArrayList<>());
            }
        }
//        // 判断话题是否可以匿名
//        ArrayList<Integer> canAnonymousTopicIdList = new ArrayList<>(Arrays.asList(TopicUserHotType.ENABLE_ANONY_TOPIC));
//        // 是否可以匿名,1不可以，2可以
//        Integer status = 1;
//        if (canAnonymousTopicIdList.contains(topicId)){
//            status = 2;
//        }
//        topicDetailVo.setStatus();
        return new Result<>(CommonEnum.SUCCESS, topicDetailVo);
    }

    /**
     * 新增话题
     *
     * @param saveTopicDto
     * @param path
     * @return
     */
    @Override
    @Deprecated
    public Result saveTopic(SaveTopicDTO saveTopicDto, MultipartFile path) throws IOException {

        Integer userId = JwtUtils.getMemberIdByJwtToken(request);

        log.info("开始执行新增话题功能");
        if (saveTopicDto.getTitle() == null) {
            ExceptionUtils.error(TopicEnum.TOPIC_TITLE_NOT_NULL);
        }
        if (saveTopicDto.getContent() == null) {
            ExceptionUtils.error(TopicEnum.TOPIC_CONTENT_NOT_NULL);
        }
        Topic topic = new Topic();
        BeanUtils.copyProperties(saveTopicDto, topic);
        topic.setUserId(userId);
        topic.setDeleteStatus(DeleteStatus.NO);

        log.info("开始执行加入图片功能");
        String paths = "XYOtoTopic";
        String url = xyOtoOss.uploadFileAvatar(path, paths);
        if (url == null) {
            ExceptionUtils.error(FileEnum.FILE_IS_NULL);
        }
        topic.setPath(url);

        log.info("开始执行SQL");
        Integer saveTopicStatus = topicMapper.saveTopic(topic);
        if (saveTopicStatus == null || saveTopicStatus == 0) {
            ExceptionUtils.error(TopicEnum.TOPIC_CREATE_FAIL);
        }
        log.info("开始执行添加进热门话题表");
        HotTopic hotTopic = new HotTopic();
        hotTopic.setTopicId(topic.getId());
        hotTopic.setCurrentHot(HotTopicInitialization.CURRENT_HOT);
        hotTopic.setTotalHot(HotTopicInitialization.TOTAL_HOT);
        Integer saveHotTopic = hotTopicMapper.saveHotTopic(hotTopic);
        if (saveHotTopic == null || saveHotTopic == 0) {
            ExceptionUtils.error(TopicEnum.HOT_TOPIC_CREAT_FAIL);
        }

        return Result.success();
    }

    /**
     * 根据分页参数获取热门话题榜
     *
     * @param hotTopicDTO
     * @return
     */
    @Override
    public Result getHotTopicList(GetHotTopicDTO hotTopicDTO) {

        // 查话题热度表，查出页数对应的话题id
        PageDTO pageDTO = hotTopicDTO.getPageDTO();
        PageHelper.startPage(pageDTO.getPageNum(), pageDTO.getPageSize());
        List<HotTopic> hotTopicList = hotTopicMapper.selectListOrderByCurrentHotDesc(hotTopicDTO.getTitle(), pageDTO.getEndIndexId());
        if (hotTopicList.size() == 0) {
            return Result.success(new PageUtils<>());
        }
        // 遍历获取每个热门话题的话题id
        List<Integer> topicIdList = hotTopicList.stream().map(HotTopic::getTopicId).collect(Collectors.toList());
        List<Topic> topicList = topicMapper.selectListBatchTopicIds(topicIdList);
        List<HotTopicVO> hotTopicVOList = new ArrayList<>();
        for (Topic topic : topicList) {
            // 获取话题下的动态数
            Integer dynamicCount = dynamicMapper.countDynamicByTopicId(topic.getId());
            // 获取话题的关注数
            Integer followCount = topicFollowMapper.countFollowByTopicId(topic.getId());
            HotTopicVO hotTopicVO = new HotTopicVO();
            hotTopicVO.setTopicId(topic.getId());
            hotTopicVO.setPath(topic.getPath());
            hotTopicVO.setTitle(topic.getTitle());
            hotTopicVO.setDynamicCount(dynamicCount);
            hotTopicVO.setFollowCount(followCount);
            hotTopicVO.setContent(topic.getContent());
            hotTopicVO.setStatus(topic.getStatus().intValue());
            hotTopicVOList.add(hotTopicVO);
        }
        // 获取分页信息
        PageUtils<HotTopicVO> hotTopicListPageInfo = PageUtils.restPage(hotTopicList, hotTopicVOList);
        return Result.success(hotTopicListPageInfo);
    }

    /**
     * 根据话题id获取热门动态，即该话题下的热门动态
     *
     * @param pageDTO
     * @param topicId
     * @return
     */
    @Override
    public Result getTopicHotDynamic(PageDTO pageDTO, Integer topicId) {
        //从热门动态缓存列表中获取最新的热门动态信息 -->返回 动态id集合，以及分页的信息
        PageUtils<Integer> dynamicPageList = topicHotDynamicCacheService.getTopicHotDynamicIdListFromCache(topicId, pageDTO);
        // 根据热门动态表里面查出来的热门动态id，去查对应的动态详情
        List<Integer> dynamicIds = dynamicPageList.getList();
        //如果动态数目为空
        if (dynamicIds == null || dynamicIds.size() == 0) {
            return Result.success(dynamicPageList);
        }
        //通过缓存处理，拼接详情数据
        List<TotalDynamicListVo> dynamicVoList = dynamicCacheService.getDynamicVoListFromCache(dynamicPageList);
        // 返回分页信息
        return Result.success(PageUtils.restPage(dynamicPageList, dynamicVoList));
    }

    /**
     * 删除话题
     * 管理员才能删除
     *
     * @param topicId 话题id
     * @return
     */
    @Override
    public Result removeTopicById(Integer topicId) {
        if (null == topicId || topicId <= 0) {
            ExceptionUtils.error(TopicEnum.TOPIC_NOT_EXIST);
        }
        if (true) {
            ExceptionUtils.error(TopicEnum.REQUEST_NOT_ALLOWED);
        }
        //todo 检验管理员
        //获取问答id集合
        //获取动态id集合
        List<Integer> dynamicIdList = dynamicMapper
                .getDynamicIdList(topicId);
        if (dynamicIdList.size() != 0) {
            for (Integer dynamicId : dynamicIdList) {
                dynamicService.removeDynamicById(dynamicId);
            }
        }
        //删除话题
        Topic topic = new Topic();
        topic.setDeleteStatus(DeleteStatus.YES);
        topic.setId(topicId);
        Integer status = topicMapper.removeTopic(topic);
        if (status != OperationStatus.SUCCESS) {
            ExceptionUtils.error(TopicEnum.TOPIC_DELETE_FAIL);
        }
        //删除缓存中的话题信息 == 异步
        topicCacheService.deleteTopicFromCache(topicId);
        return Result.success();
    }

    /**
     * 话题审核
     *
     * @param dto
     * @return
     */
    @Override
    public Result saveTopicExamine(SaveTopicDTO dto) {
        /**
         * 判断创建话题的条件
         * 1、完成学生认证
         * 2、活跃度200
         */
        //获取当前用户id
        Integer userId = JwtUtils.getMemberIdByJwtToken(request);

        //V1.0 版本 不介入学生认证
//        //校验学生认证
//        Short status = studentAuthenticationMapper.getStatus(userId);
//        if (!AuthenticationStatus.APPROVED_SUCCESS.equals(status)) {
//            ExceptionUtils.error(StudentAuthenticationEnum.NOT_AUTHENTICATION);
//        }
        //校验活跃度
        Integer hot = userMapper.getHot(userId);
        if (hot <= HotTopicInitialization.TOPIC_HOT) {
            ExceptionUtils.error(TopicEnum.USER_ACTIVITY_NOT_ENOUGH);
        }
        Topic topic = new Topic();
        topic.setPath(dto.getPath());
        topic.setUserId(userId);
        topic.setDeleteStatus(DeleteStatus.NO);
        topic.setContent(dto.getContent());
        topic.setTitle(dto.getTitle());
        topic.setAuthenticationStatus(AuthenticationStatus.APPROVING);
        Integer stats = topicMapper.saveTopic(topic);
        if (stats != OperationStatus.SUCCESS) {
            ExceptionUtils.error(TopicEnum.TOPIC_CREATE_FAIL);
        }
        // 给动态主人加活跃度
        topicUserHotService.addHot(topic.getUserId(), topic.getId(), TopicUserHotType.PUBLISH_TOPIC);

        //添加到话题缓存中 === 异步
        topicCacheService.addTopicToCache(topic);
        return Result.success();
    }

    @Override
    public Result getTopicAllDynamic(PageDTO pageDTO, Integer topicId) {
        int pageNum = pageDTO.getPageNum();
        int pageSize = pageDTO.getPageSize();
        //获取动态分页处理对象
        PageUtils<Integer> dynamicPage = new PageUtils<>();
        //判断要取的数据是否需要在DB中查找
        int page = CacheInstruction.LATEST_DYNAMIC_MAX_COUNT / pageSize;
        if (pageNum <= page) {
            //从缓存中获取全部动态的列表
            //获取分页处理后的对象
            dynamicPage = topicAllDynamicCacheService.getTopicAllDynamicIdListFromCache(topicId, pageDTO);
            if (dynamicPage.getList().size() == 0){
                //没有可使用的数据
                return Result.success(dynamicPage);
            }
            List<TotalDynamicListVo> dynamicVoList = dynamicCacheService.getDynamicVoListFromCache(dynamicPage);
            return Result.success(PageUtils.restPage(dynamicPage, dynamicVoList));
        } else {
            //大于缓存中的页数，从数据库中查找
            PageHelper.startPage(pageNum, pageSize);
            List<TotalDynamicListPO> totalDynamicList = dynamicMapper.getTotalDynamicList(pageDTO.getEndIndexId());
            long startTime = System.currentTimeMillis();
            List<TotalDynamicListVo> dynamicVoList = dynamicService.getDynamicVoList(totalDynamicList, pageDTO);
            System.out.println("拼装VO所需要 时间为" + (System.currentTimeMillis() - startTime));
            return Result.success(PageUtils.restPage(dynamicPage, dynamicVoList));
        }
    }


    @Override
    public Result getTopicUserHotList(Integer topicId) {
        if (topicId == null || topicId <= 0) {
            ExceptionUtils.error(CommonEnum.REQUEST_PARAM_ERROR);
        }
        //根据话题id获取表名
        Type2TopicUserHotTableInfo topicUserHotInfoByTopicId = topicUserHotTableConfig.getTopicUserHotInfoByTopicId(topicId);
        if (topicUserHotInfoByTopicId == null) {
            return Result.success(new ArrayList<>());
        }
        //存储用户信息
        List<Integer> list = new ArrayList<>();
        List<TopicUerHotVo> hotUserList = new ArrayList<>();
        Set<ZSetOperations.TypedTuple<Object>> typedTuples = redisCommonUtils.rangeByZSetWithScore(topicUserHotInfoByTopicId.getTableName(), 0, 9);
        //将值转换为
        for (ZSetOperations.TypedTuple<Object> typedTuple : typedTuples) {
            TopicUerHotVo topicUerHotVo = new TopicUerHotVo();
            //保存用户id
            Integer userId = Integer.parseInt(Objects.requireNonNull(typedTuple.getValue()).toString());
            list.add(userId);
            topicUerHotVo.setUserId(userId);
            //保存用户热度值
            topicUerHotVo.setScore(Objects.requireNonNull(typedTuple.getScore()).intValue());
            hotUserList.add(topicUerHotVo);
        }
        //查询用户信息
        HashMap<Integer, UserPO> userMap = new HashMap<>();
        if (hotUserList.size() != 0) {
            List<UserPO> userSimpleList = userMapper.getUserSimpleList(list);
            for (UserPO userPO : userSimpleList) {
                userMap.put(userPO.getId(), userPO);
            }
            //拼装用户信息
            for (TopicUerHotVo topicUerHotVo : hotUserList) {
                UserPO userPO = userMap.get(topicUerHotVo.getUserId());
                topicUerHotVo.setNickName(userPO.getNickname());
                topicUerHotVo.setAvatarUrl(userPO.getAvatarUrl());
                // 获取头衔
                UserTitlePO userTitlePo = userTitleCacheService.getUserTitleFromCache(userPO.getTitleNameId(), userPO.getTitleLogoId());
                topicUerHotVo.setUserTitlePO(userTitlePo);

            }
        }
        return Result.success(hotUserList);
    }

    /**
     * 根据话题id列表获取一组TopicListVo
     *
     * @param topicIdList 话题id
     * @return
     */
    @Override
    public List<TopicListVo> listTopicBatchTopicIds(List<Integer> topicIdList) {
        if (topicIdList.size() == 0) {
            return new ArrayList<>();
        }
        List<TopicListVo> topicListVoList = topicMapper.selectBatchTopicIds(topicIdList);
        // 填充统计数据
        fillCount(topicListVoList);
        return topicListVoList;
    }

    /**
     * 修改话题
     *
     * @param updateTopicDTO
     * @return {@link Result}
     * @author 廖振辉
     */
    @Override
    public Result updateTopicById(UpdateTopicDTO updateTopicDTO) {
        if (updateTopicDTO.getTopicId() == null) {
            ExceptionUtils.error(TopicEnum.TOPIC_NOT_EXIST);
        }
        Topic topic = topicMapper.selectOneByTopicId(updateTopicDTO.getTopicId());
        if (topic == null) {
            ExceptionUtils.error(TopicEnum.TOPIC_NOT_EXIST);
        }
        if (!StringUtils.isEmpty(updateTopicDTO.getTitle())) {
            topic.setTitle(updateTopicDTO.getTitle());
        }
        if (!StringUtils.isEmpty(updateTopicDTO.getContent())) {
            topic.setContent(updateTopicDTO.getContent());
        }
        if (updateTopicDTO.getMultipartFile() != null) {
            try {
                String path = xyOtoOss.uploadFileAvatar(updateTopicDTO.getMultipartFile(), OssBucketModuleName.TOPIC);
                topic.setPath(path);
            } catch (IOException e) {
                ExceptionUtils.error(PictureEnum.PICTURE_UPLOAD_ERROR);
            }
        }
        Integer update = topicMapper.updateByTopicId(topic);
        if (update < DatabaseOperationResult.SUCCESS) {
            ExceptionUtils.error(TopicEnum.TOPIC_SAVE_ERROR);
        }
        //更新缓存中的话题信息  == 异步
        topicCacheService.updateTopicFromCache(topic);
        return Result.success(topic);
    }
}
